package main

import (
	"bytes"
	"compress/gzip"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/tls"
	"encoding/base64"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/spf13/cast"
	"gopkg.in/yaml.v2"
)

var (
	version       string
	flagGetConfig = flag.String(`GenConfig`, ``, `generate config example file`)
	flagCfg       = flag.String(`cfg`, `config.cfg`, `config file`)
	flagVersion   = flag.Bool(`version`, false, `print version info`)
)

var letterRunes = []rune("abcdefghiKLMN0123456789OPQRSTUVWXYZ")

var (
	funcMap = template.FuncMap{"randstr": RandStringRunes, "timenow": getNow}
)

var (
	configExample = ``
)

func init() {
	//定义日志文件
	f, err := os.OpenFile("mockdata.log", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		panic(err)
	}
	//定义日志格式,prefix为日志行首的信息，暂时为空吧，没啥信息
	// mocklog = log.New(f, "", log.Ldate|log.Ltime|log.Lshortfile)
	log.SetOutput(f)
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type Config struct {
	Clients []Client `yaml:"clients"`
}

type Client struct {
	Dataway        string            `yaml:"dataway"`
	Precision      string            `yaml:"precision"`
	Query          map[string]string `yaml:"query"`
	DatakitUuid    []string          `yaml:"datakit_uuid"`
	DatakitVersion []string          `yaml:"datakit_version"`
	Metrics        []Metric          `yaml:"metrics"`
}

type Auth struct {
	AccessKey string `yaml:"access_key"`
	SecretKey string `yaml:"secret_key"`
}

type Metric struct {
	Measurment string                   `yaml:"measurment"`
	Interval   string                   `yaml:"interval"`  //采集频率
	Precision  string                   `yaml:"precision"` //时间精度
	Query      map[string]string        `yaml:"query"`
	Header     map[string]string        `yaml:"header"`
	Tags       []Tag                    `yaml:"tags"`
	Extend     map[string][]interface{} `yaml:"extend"`
	Auths      Auth                     `yaml:"auth"`
	Fields     []Field                  `yaml:"fields"`
	TimeSet    TimeSet                  `yaml:"time_set"`   //时间设置
	Count      int                      `yaml:"count"`      //计数
	Limit      int                      `yaml:"limit"`      //限制数量
	CacheData  strings.Builder          `yaml:"cache_data"` //缓存一定量(缓存数)的数据
	CacheNum   int                      `yaml:"cache_num"`  //缓存数
	CacheCount int
	Path       string `yaml:"path"` //自定义path
	Gzip       bool   `yaml:"gzip"`
}

// 时间设置
type TimeSet struct {
	Years   int `yaml:"years"`
	Months  int `yaml:"months"`
	Days    int `yaml:"days"`
	Hours   int `yaml:"hours"`
	Mins    int `yaml:"mins"`
	Seconds int `yaml:"seconds"`
	History struct {
		Unit string `yaml: unit`
		Step int    `yaml: step`
	} `yaml:"history"`
}

type Tag struct {
	Key   string   `yaml:"key"`
	Value []string `yaml:"value"`
}

type Field struct {
	Key       string   `yaml:"key"`
	Value     []string `yaml:"value"`
	Type      string   `yaml:"type"`
	Operation struct {
		Key   string `yaml:"key"`
		Value string `yaml:"value"`
	} `yaml:"operation"`
}

type mytime struct {
	time.Time
}

func (t mytime) AddDate(years int, months int, days int, hours int, mins int, second int) time.Time {
	year, month, day := t.Date()
	hour, min, sec := t.Clock()
	return time.Date(year+years, month+time.Month(months), day+days, hour+hours, min+mins, sec+second, t.Nanosecond(), t.Location())
}

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	flag.Parse()
	if *flagVersion {
		fmt.Println(version)
	}
	if *flagGetConfig != "" {
		f, err := os.OpenFile(*flagGetConfig, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
		if err != nil {
			panic(err)
		}
		_, err = f.WriteString(configExample)
		defer f.Close()
		if err != nil {
			panic(err)
		}
		os.Exit(0)
	}

	if *flagCfg != "" {
		var d Config

		f, err := os.Open(*flagCfg)
		if err != nil {
			log.Fatalln(err)
			return
		}
		defer f.Close()

		data, err := ioutil.ReadAll(f)
		if err != nil {
			log.Fatalln(err)
			return
		}
		yaml.Unmarshal(data, &d)
		log.Println(d)
		if d.Clients == nil {
			log.Fatalln("yaml解析出错，无法读取配置文件")
		}

		for _, k := range d.Clients {
			go send(k)

		}
		for {
			time.Sleep(time.Second * 1)
		}
	}

}

var do http.Client

func send(c Client) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	do.Transport = tr
	do.Timeout = time.Duration(30 * time.Second)
	//先判断是否有指定路由，如果有则随机选一个
	for _, metric := range c.Metrics {
		m := metric
		go func(c Client, m *Metric) {
			for {
				if m.Count < m.Limit || m.Limit == 0 {
					sendbody(c, m, "")
					time.Sleep(getSleep(m))
				} else {
					log.Println(m.Measurment, "满足limit数量", m.Limit, "限制,不再发送数据")
					time.Sleep(1 * time.Minute)
				}

			}
		}(c, &m)
	}
}

func sendbody(c Client, m *Metric, body string) {
	stime := time.Now().UnixNano() / 1e6  //开始时间
	newdataway := getDatawayAddress(c, m) //发送数据地址
	log.Println(newdataway)
	//获取发送内容
	if body == "" {
		body = getBody(c, m)
	}
	data_func, _ := template.New("test").Funcs(funcMap).Parse(body)
	buf := new(bytes.Buffer)
	data_func.Execute(buf, nil)
	body = buf.String()
	//加密数据发送
	if m.Auths.AccessKey != "" && m.Auths.SecretKey != "" {
		//判断数据是否需要缓存
		if m.CacheNum > 0 && m.CacheCount < m.CacheNum {
			_, err := m.CacheData.WriteString(body + "\n")
			if err != nil {
				fmt.Println(err)
			}
			m.CacheCount += 1 //缓存数加1
			m.Count += 1      //总数加1
			return
		} else if m.CacheNum > 0 && m.CacheCount == m.CacheNum { //满足缓存数量发送数据
			dates := fmt.Sprintf("%s", time.Now().UTC().Format(http.TimeFormat))
			log.Println(m.CacheData.String())
			fmt.Println(m.CacheData.String())
			m5 := getMd5([]byte(m.CacheData.String()))
			sign := signature(m.Auths.AccessKey, m.Auths.SecretKey, m5, dates)
			req, err := http.NewRequest("POST", newdataway, bytes.NewReader([]byte(m.CacheData.String())))
			if err != nil {
				log.Println(err)
			}
			for k, v := range m.Header {
				req.Header.Add(k, v)
			}
			req.Header.Add("User-Agent", "go/http")
			req.Header.Add("Content-Type", "text/plain")
			req.Header.Add("X-Datakit-UUID", getDataKitUUid(c.DatakitUuid))
			req.Header.Add("X-Version", getVersion(c.DatakitVersion))
			req.Header.Add("Date", dates)
			// req.Header.Add("Content-Encoding", "gzip")
			req.Header.Add("Authorization", sign)
			resp, err := do.Do(req)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Println(err)
			}
			log.Println("响应", resp.StatusCode, string(b))
			m.CacheData.Reset() //把已发送的缓存数据清掉
			m.CacheCount = 0    //把缓存数重置掉，准备下一轮缓存
		} else { //不需要缓存
			dates := fmt.Sprintf("%s", time.Now().UTC().Format(http.TimeFormat))
			log.Println(body)
			fmt.Println(body)
			m5 := getMd5([]byte(body))
			sign := signature(m.Auths.AccessKey, m.Auths.SecretKey, m5, dates)
			req, err := http.NewRequest("POST", newdataway, bytes.NewReader([]byte(body)))
			if err != nil {
				fmt.Println(err)
				return
			}
			for k, v := range m.Header {
				req.Header.Add(k, v)
			}
			req.Header.Add("User-Agent", "go/http")
			req.Header.Add("Content-Type", "text/plain")
			req.Header.Add("X-Datakit-UUID", getDataKitUUid(c.DatakitUuid))
			req.Header.Add("X-Version", getVersion(c.DatakitVersion))
			req.Header.Add("Date", dates)
			req.Header.Add("Authorization", sign)
			resp, err := do.Do(req)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Println(err)
			}
			log.Println("响应", resp.StatusCode, string(b))
			m.Count += 1
			return
		}
	} else {
		//不加密数据
		//是否需要把数据缓存到一定的量
		if m.CacheNum > 0 && m.CacheCount < m.CacheNum {
			_, err := m.CacheData.WriteString(body + "\n")
			if err != nil {
				fmt.Println(err)
			}
			m.CacheCount += 1
			m.Count += 1
			return
		} else if m.CacheNum > 0 && m.CacheCount == m.CacheNum { // 满足缓存条件，准备发送
			if m.Gzip {
				var gzbuf bytes.Buffer
				gz := gzip.NewWriter(&gzbuf)
				gz.Write([]byte(m.CacheData.String()))
				gz.Flush()
				m.CacheData.Reset()
				m.CacheData.WriteString(string(gzbuf.Bytes()))
			}
			req, err := http.NewRequest("POST", newdataway, bytes.NewReader([]byte(m.CacheData.String())))
			fmt.Println(m.CacheData.String())
			log.Println(m.CacheData.String())
			if err != nil {
				fmt.Println(err)
				return
			}

			req.Header.Add("Content-Type", "text/plain")
			if m.Gzip {
				req.Header.Add("Content-Encoding", "gzip")
			}
			req.Header.Add("X-Datakit-UUID", getDataKitUUid(c.DatakitUuid))
			req.Header.Add("X-Version", getVersion(c.DatakitVersion))
			for k, v := range m.Header {
				req.Header.Add(k, v)
			}
			//req.Header.Add("X-Precision","h")
			resp, err := do.Do(req)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Println(err)
			}
			log.Println("响应", resp.StatusCode, string(b))
			m.CacheCount = 0
			m.CacheData.Reset()
			return
		} else {
			fmt.Println(body)
			if m.Gzip {
				var gzbuf bytes.Buffer
				gz := gzip.NewWriter(&gzbuf)
				gz.Write([]byte(body))
				gz.Flush()
				body = string(gzbuf.Bytes())
				fmt.Println(body)

			}
			req, err := http.NewRequest("POST", newdataway, bytes.NewReader([]byte(body)))
			if err != nil {
				log.Println(err)
			}
			req.Header.Add("Content-Type", "text/plain")
			if m.Gzip {
				req.Header.Add("Content-Encoding", "gzip")
			}
			req.Header.Add("X-Datakit-UUID", getDataKitUUid(c.DatakitUuid))
			req.Header.Add("X-Version", getVersion(c.DatakitVersion))
			for k, v := range m.Header {
				req.Header.Add(k, v)
			}
			//req.Header.Add("X-Precision","h")
			resp, err := do.Do(req)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Println(err)
			}
			log.Println("响应", resp.StatusCode, string(b))
		}
		etime := time.Now().UnixNano() / 1e6
		cost := etime - stime
		log.Println("耗时(秒):", float64(cost)/1000)
		//计数
		m.Count += 1
		return
	}
}

func getSleep(m *Metric) time.Duration {
	d, err := time.ParseDuration(m.Interval)
	if err != nil {
		log.Println(err)
	}
	return d
}

func getTags(m *Metric, exclude []string) string {
	tags := []string{}
	//组织tag信息
	for _, t := range m.Tags {
		//排除过滤tag
		if !inArray(t.Key, exclude) {
			//模板渲染
			f, _ := template.New("test").Funcs(funcMap).Parse(t.Key)
			buf := new(bytes.Buffer)
			f.Execute(buf, nil)
			tagkeyV := buf.String()

			tagkey := escape(tagkeyV)
			//

			//判断是否有多个value，随机选取一个
			if len(t.Value) > 0 {
				i := randint(0, len(t.Value))
				r := t.Value[i]

				//模板渲染
				t, _ := template.New("test").Funcs(funcMap).Parse(r)
				buf := new(bytes.Buffer)
				t.Execute(buf, nil)
				r = buf.String()

				//是否需要很多的tag value
				if _, ok := m.Extend["递增"]; ok {
					for _, item := range m.Extend["递增"] {
						if rec, ok := item.(map[interface{}]interface{}); ok {
							if rec["递增tagKey"] != nil && rec["递增tagKey"].(bool) && rec["max"] != nil && m.Count <= rec["max"].(int) {
								tagkey += strconv.Itoa(m.Count)
							}
							if rec["递增tagValue"] != nil && rec["递增tagValue"].(bool) && rec["max"] != nil && m.Count <= rec["max"].(int) {
								r += strconv.Itoa(m.Count)
							}
						}
					}
				}
				tags = append(tags, tagkey+"="+escape(r))
			}
		}
	}
	//当某tag等于某值的时候，剔除一些tag
	if _, ok := m.Extend["Exclude"]; ok {
		newtags := map[string]string{}
		for _, item := range tags {
			data := strings.Split(item, "=")
			newtags[data[0]] = data[1]
		}
		for _, item := range m.Extend["Exclude"] {
			if rec, ok := item.(map[interface{}]interface{}); ok {
				for _, v := range rec["value"].([]interface{}) {
					if newtags[rec["满足tag"].(string)] == v.(string) {
						for _, m := range rec["排除tag"].([]interface{}) {
							delete(newtags, m.(string))
						}
					}
				}

			}
		}

		new2 := []string{}
		for k, v := range newtags {
			new2 = append(new2, k+"="+v)
		}
		return strings.Join(new2, ",")
	}

	return strings.Join(tags, ",")
}

func inArray(item string, items []string) bool {
	for _, i := range items {
		if i == item {
			return true
		}
	}
	return false
}

func getFields(m *Metric, exclude []string) string {
	fields := []string{}
	for _, f := range m.Fields {
		if !inArray(f.Key, exclude) {
			//是否需要递增field
			if _, ok := m.Extend["递增"]; ok {
				for _, item := range m.Extend["递增"] {
					if rec, ok := item.(map[interface{}]interface{}); ok {
						if rec["递增field"] != nil && rec["递增field"].(bool) && rec["max"] != nil && m.Count <= rec["max"].(int) {
							f.Key += strconv.Itoa(m.Count)
						}
					}
				}
			}
			//判断数据类型
			switch f.Type {
			case "str":
				//判断是否有多个value，随机选一个
				if len(f.Value) > 0 {
					i := randint(0, len(f.Value))
					r := f.Value[i]

					//模板渲染
					t, _ := template.New("test").Funcs(funcMap).Parse(r)
					buf := new(bytes.Buffer)
					t.Execute(buf, nil)
					r = buf.String()
					fields = append(fields, escape(f.Key)+"=\""+stringFieldEscape(r)+"\"")

				}
			case "int":
				//判断是一个值，还是2个值
				if len(f.Value) != 2 && len(f.Value) > 0 {
					i := randint(0, len(f.Value))
					var newV interface{}
					switch f.Operation.Key {
					case "+":
						newV = cast.ToInt(f.Value[i]) + cast.ToInt(f.Operation.Value)*m.Count
					case "-":
						newV = cast.ToInt(f.Value[i]) - cast.ToInt(f.Operation.Value)*m.Count
					case "*":
						newV = cast.ToInt(f.Value[i]) * cast.ToInt(math.Pow(cast.ToFloat64(f.Operation.Value), float64(m.Count)))
					case "/":
						newV = cast.ToInt(f.Value[i]) / cast.ToInt(f.Operation.Value) * m.Count
					default:
						newV = f.Value[i]
					}
					fields = append(fields, escape(f.Key)+"="+cast.ToString(newV)+"i")
				} else if len(f.Value) == 2 {
					start, err := strconv.Atoi(f.Value[0])
					if err != nil {
						log.Println(err)
					}
					end, err := strconv.Atoi(f.Value[1])
					if err != nil {
						log.Println(err)
					}
					if end > start {
						i := randint(start, end)
						fields = append(fields, escape(f.Key)+"="+strconv.Itoa(i)+"i")
					} else {
						i := randint(end, start)
						fields = append(fields, escape(f.Key)+"="+strconv.Itoa(i)+"i")
					}
				}
			case "float":
				//判断是一个值，还是2个值
				if len(f.Value) != 2 && len(f.Value) > 0 {
					i := randint(0, len(f.Value))
					var newV interface{}
					switch f.Operation.Key {
					case "+":
						newV = cast.ToFloat64(f.Value[i]) + cast.ToFloat64(f.Operation.Value)*cast.ToFloat64(m.Count)
					case "-":
						newV = cast.ToFloat64(f.Value[i]) - cast.ToFloat64(f.Operation.Value)*cast.ToFloat64(m.Count)
					case "*":
						newV = cast.ToFloat64(f.Value[i]) * cast.ToFloat64(f.Operation.Value) * cast.ToFloat64(m.Count)
					case "/":
						newV = cast.ToFloat64(f.Value[i]) / cast.ToFloat64(f.Operation.Value) * cast.ToFloat64(m.Count)
					default:
						newV = f.Value[i]
					}
					fields = append(fields, escape(f.Key)+"="+cast.ToString(newV))
				} else if len(f.Value) == 2 {
					start, err := strconv.Atoi(f.Value[0])
					if err != nil {
						log.Println(err)
					}
					end, err := strconv.Atoi(f.Value[1])
					if err != nil {
						log.Println(err)
					}
					if end > start {
						i := randfloat(start, end)
						fields = append(fields, escape(f.Key)+"="+fmt.Sprintf("%.6f", i))

					} else {
						i := randfloat(start, end)
						fields = append(fields, escape(f.Key)+"="+fmt.Sprintf("%.6f", i))
					}
				}
			case "boolean":
				//判断是否有多个value，随机选一个
				if len(f.Value) > 0 {
					i := randint(0, len(f.Value))
					r := f.Value[i]
					fields = append(fields, escape(f.Key)+"="+stringFieldEscape(r))
				}

			}
		}
	}
	return strings.Join(fields, ",")
}

func getDatawayAddress(c Client, m *Metric) string {
	//定义新路由地址
	//把参数统一加上
	u, err := url.ParseRequestURI(c.Dataway)
	queryup := map[string]string{}

	if len(u.RawQuery) > 0 {
		query := strings.Split(u.RawQuery, "&")
		if len(query) > 0 {
			for _, item := range query {
				t := strings.Split(item, "=")
				if len(t) == 2 {
					queryup[t[0]] = t[1]
				} else {
					queryup[t[0]] = "1"
				}
			}

		}
	}

	if err != nil {
		log.Fatalln(err)
	}

	//把指标需要发送到dataway，定义的querey参数加上
	// queryup := map[string]string{}
	//把客户端参数加上
	for k, v := range c.Query {
		queryup[k] = v
	}
	//把指标参数加上
	for k, v := range m.Query {
		queryup[k] = v
	}
	//连接成key=value&key=value模式
	q := []string{}
	for k, v := range queryup {
		q = append(q, k+"="+v)
	}
	u.RawQuery = strings.Join(q, "&")

	if m.Path != "" {
		u.Path = m.Path
	}

	newdataway := u.Scheme + ":" + "//" + u.Host + u.Path + "?" + u.RawQuery
	return newdataway
}

func getTime(c Client, m *Metric) string {
	//自定义时间
	mt := mytime{time.Now()}

	switch m.TimeSet.History.Unit {
	case "seconds":
		m.TimeSet.Seconds += m.TimeSet.History.Step
	case "hours":
		m.TimeSet.Hours += m.TimeSet.History.Step
	case "mins":
		m.TimeSet.Mins += m.TimeSet.History.Step
	case "days":
		m.TimeSet.Days += m.TimeSet.History.Step
	case "months":
		m.TimeSet.Months += m.TimeSet.History.Step
	case "years":
		m.TimeSet.Years += m.TimeSet.History.Step

	}

	//增减时间
	ct := mt.AddDate(m.TimeSet.Years, m.TimeSet.Months, m.TimeSet.Days, m.TimeSet.Hours, m.TimeSet.Mins, m.TimeSet.Seconds)

	//根据时间单位降精度
	if m.Precision == "" && c.Precision == "" {
		return fmt.Sprintf("%v", ct.UnixNano())
	} else {
		if m.Precision != "" {
			return precision(ct, m.Precision)
		} else if c.Precision != "" {
			return precision(ct, c.Precision)
		}
		return fmt.Sprintf("%v", ct.UnixNano())
	}
}

func precision(ct time.Time, pre string) string {
	//t:=time.Unix(ct.Unix(),ct.UnixNano())

	switch pre {
	case "h":
		return fmt.Sprintf("%v", ct.Unix()/3600)
	case "m":
		return fmt.Sprintf("%v", ct.Unix()/60)
	case "s":
		return fmt.Sprintf("%v", ct.Unix())
	case "ms":
		return fmt.Sprintf("%v", ct.UnixNano()/1e6)
	case "us", "µs":
		return fmt.Sprintf("%v", ct.UnixNano()/1000)
	case "ns":
		return fmt.Sprintf("%v", ct.UnixNano())
	default:
		return fmt.Sprintf("%v", ct.UnixNano())
	}
}

func randint(min, max int) int {
	rand.Seed(time.Now().UnixNano())
	num := min + rand.Intn(max-min)
	return num
}

func randfloat(min, max int) float64 {
	rand.Seed(time.Now().UnixNano())
	num := min + rand.Intn(max-min)
	result := rand.Float64() * float64(num)
	if result < float64(min) {
		result = result + float64(min)
	}
	return result
}

func signature(ak, secret string, ContentMD5 string, t string) string {
	array := []string{"POST", ContentMD5, "text/plain", t}
	data := strings.Join(array, "\n")
	m := hmac.New(sha1.New, []byte(secret))
	io.WriteString(m, data)
	sg := base64.StdEncoding.EncodeToString(m.Sum(nil))
	return "DWAY " + ak + ":" + sg
}

func getMd5(data []byte) string {
	bm := md5.Sum(data)
	return base64.StdEncoding.EncodeToString(bm[:])

}

func getBody(c Client, m *Metric) string {
	tags := getTags(m, nil)
	fields := getFields(m, nil)
	t := getTime(c, m)
	metric := m.Measurment

	//模板渲染
	tp, _ := template.New("test").Funcs(funcMap).Parse(metric)
	buf := new(bytes.Buffer)
	tp.Execute(buf, nil)
	metric = nameEscape(buf.String())

	//判断metric是否需要递增,例如: mem1,mem2,mem3
	if _, ok := m.Extend["递增"]; ok {
		for _, item := range m.Extend["递增"] {
			if rec, ok := item.(map[interface{}]interface{}); ok {

				if rec["递增metric"] != nil && rec["递增metric"].(bool) && rec["max"] != nil && m.Count <= rec["max"].(int) {
					metric += strconv.Itoa(m.Count)
				}
			}
		}
	}
	//metric,判断tag是否为空，如果tag为空则
	if len(tags) > 0 {
		body := metric + "," + tags + " " + fields + " " + t
		return body
	} else {
		body := metric + " " + fields + " " + t
		return body
	}
}

// 获取version
func getVersion(version []string) string {
	datakitversion := ""
	if len(version) > 0 {
		i := randint(0, len(version))
		datakitversion = version[i]
	} else {
		datakitversion = "v0.1"
	}
	return datakitversion
}

// 获取UUID
func getDataKitUUid(dkuuids []string) string {
	datakituuid := ""
	if len(dkuuids) > 0 {
		i := randint(0, len(dkuuids))
		datakituuid = dkuuids[i]
	} else {
		datakituuid = "mockdata"
	}
	return datakituuid
}

// 安全转义，metric ，field，tag
const (
	escapes            = "\t\n\f\r ,="
	nameEscapes        = "\t\n\f\r ,"
	stringFieldEscapes = "\t\n\f\r\\\""
)

var (
	escaper = strings.NewReplacer(
		"\t", `\t`,
		"\n", `\n`,
		"\f", `\f`,
		"\r", `\r`,
		`,`, `\,`,
		` `, `\ `,
		`=`, `\=`,
	)

	nameEscaper = strings.NewReplacer(
		"\t", `\t`,
		"\n", `\n`,
		"\f", `\f`,
		"\r", `\r`,
		`,`, `\,`,
		` `, `\ `,
	)

	stringFieldEscaper = strings.NewReplacer(
		`"`, `\"`,
		`\`, `\\`,
	)
)

// Escape a tagkey, tagvalue, or fieldkey
func escape(s string) string {
	if strings.ContainsAny(s, escapes) {
		return escaper.Replace(s)
	} else {
		return s
	}
}

// Escape a measurement name
func nameEscape(s string) string {
	if strings.ContainsAny(s, nameEscapes) {
		return nameEscaper.Replace(s)
	} else {
		return s
	}
}

// Escape a string field
func stringFieldEscape(s string) string {
	if strings.ContainsAny(s, stringFieldEscapes) {
		return stringFieldEscaper.Replace(s)
	} else {
		return s
	}
}

func RandStringRunes(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func getNow(d string) int64 {
	switch strings.ToLower(d) {

	case "s":
		return time.Now().Unix()
	case "ms":
		return time.Now().UnixNano() / 1e6
	case "us", "µs":
		return time.Now().UnixNano() / 1000
	case "ns":
		return time.Now().UnixNano()
	default:
		return time.Now().Unix()
	}
}

type M struct {
	Name   string                 `json:"name"`
	Tags   map[string]string      `json:"tags"`
	Fields map[string]interface{} `json:"fields"`
	Time   string                 `json:"time"`
}

type Trace struct {
	TraceId       string            `json:"traceId"`
	Id            string            `json:"id"`
	Name          string            `json:"name"`
	Timestamp     int               `json:"timestamp"`
	Duration      int               `json:"Duration"`
	LocalEndpoint map[string]string `json:"localEndpoint"`
	Tags          map[string]string `json:"tags"`
}
